home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / mac / DirectX SDK / DXSDK / samples / Multimedia / Direct3D / Lighting / lighting.cpp < prev    next >
C/C++ Source or Header  |  2001-10-08  |  16KB  |  443 lines

  1. //-----------------------------------------------------------------------------
  2. // File: Lighting.cpp
  3. //
  4. // Desc: Example code showing how to use D3D lights.
  5. //
  6. // Copyright (c) 1995-2001 Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #define STRICT
  9. #include <windows.h>
  10. #include <basetsd.h>
  11. #include <math.h>
  12. #include <stdio.h>
  13. #include <D3DX8.h>
  14. #include <tchar.h>
  15. #include "D3DApp.h"
  16. #include "D3DFont.h"
  17. #include "D3DUtil.h"
  18. #include "DXUtil.h"
  19.  
  20.  
  21.  
  22.  
  23. //-----------------------------------------------------------------------------
  24. // Defines, constants, and global variables
  25. //-----------------------------------------------------------------------------
  26.  
  27. // Custom D3D vertex format used by the vertex buffer
  28. struct MYVERTEX
  29. {
  30.     D3DXVECTOR3 p;       // vertex position
  31.     D3DXVECTOR3 n;       // vertex normal
  32. };
  33.  
  34. #define D3DFVF_MYVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL)
  35.  
  36.  
  37.  
  38. //-----------------------------------------------------------------------------
  39. // Name: class CMyD3DApplication
  40. // Desc: Application class. The base class (CD3DApplication) provides the 
  41. //       generic functionality needed in all Direct3D samples. CMyD3DApplication 
  42. //       adds functionality specific to this sample program.
  43. //-----------------------------------------------------------------------------
  44. class CMyD3DApplication : public CD3DApplication
  45. {
  46.     LPDIRECT3DVERTEXBUFFER8 m_pWallVB; // Vertex buffer for the walls and floor
  47.     LPD3DXMESH m_pSphereMesh;          // Representation of point light
  48.     LPD3DXMESH m_pConeMesh;            // Representation of dir/spot light
  49.     CD3DFont* m_pFont;                 // Font for drawing text
  50.     D3DLIGHT8 m_light;                 // Description of the D3D light
  51.     UINT m_n;                          // Number of vertices in the ground grid along X
  52.     UINT m_m;                          // Number of vertices in the ground grid along Z
  53.     UINT m_nTriangles;                 // Number of triangles in the ground grid
  54.  
  55. protected:
  56.     HRESULT InitDeviceObjects();
  57.     HRESULT RestoreDeviceObjects();
  58.     HRESULT InvalidateDeviceObjects();
  59.     HRESULT DeleteDeviceObjects();
  60.     HRESULT FrameMove();
  61.     HRESULT Render();
  62.     HRESULT FinalCleanup();
  63.  
  64. public:
  65.     CMyD3DApplication();
  66. };
  67.  
  68.  
  69. CMyD3DApplication g_d3dApp;
  70.  
  71.  
  72. //-----------------------------------------------------------------------------
  73. // Name: WinMain()
  74. // Desc: Entry point to the program. Initializes everything, and goes into a
  75. //       message-processing loop. Idle time is used to render the scene.
  76. //-----------------------------------------------------------------------------
  77. INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
  78. {
  79.     if( FAILED( g_d3dApp.Create( hInst ) ) )
  80.         return 0;
  81.  
  82.     return g_d3dApp.Run();
  83. }
  84.  
  85.  
  86.  
  87.  
  88. //-----------------------------------------------------------------------------
  89. // Name: CMyD3DApplication()
  90. // Desc: Application constructor. Sets attributes for the app.
  91. //-----------------------------------------------------------------------------
  92. CMyD3DApplication::CMyD3DApplication()
  93. {
  94.     m_strWindowTitle            = TEXT( "Lighting" );
  95.     m_bUseDepthBuffer           = FALSE;
  96.  
  97.     m_pFont                     = new CD3DFont( _T("Arial"), 12, D3DFONT_BOLD );
  98.     m_pWallVB                   = NULL;
  99.     m_pSphereMesh               = NULL;
  100.     m_pConeMesh                 = NULL;
  101.  
  102.     // Set up wall/floor mesh resolution.  Try changing m_n and m_m to see
  103.     // how the lighting is affected.
  104.     m_n = 32;
  105.     m_m = 32;
  106.     m_nTriangles = (m_n-1)*(m_m-1)*2;
  107. }
  108.  
  109.  
  110.  
  111.  
  112. //-----------------------------------------------------------------------------
  113. // Name: InitDeviceObjects()
  114. // Desc: Initialize scene objects.
  115. //-----------------------------------------------------------------------------
  116. HRESULT CMyD3DApplication::InitDeviceObjects()
  117. {
  118.     HRESULT hr;
  119.  
  120.     if( FAILED( hr = m_pFont->InitDeviceObjects( m_pd3dDevice ) ) )
  121.         return hr;
  122.  
  123.     return S_OK;
  124. }
  125.  
  126.  
  127.  
  128.  
  129. //-----------------------------------------------------------------------------
  130. // Name: RestoreDeviceObjects()
  131. // Desc: Restores scene objects.
  132. //-----------------------------------------------------------------------------
  133. HRESULT CMyD3DApplication::RestoreDeviceObjects()
  134. {
  135.     MYVERTEX* v;
  136.  
  137.     // Create a square grid m_n*m_m for rendering the wall
  138.     if( FAILED( m_pd3dDevice->CreateVertexBuffer( m_nTriangles*3*sizeof(MYVERTEX),
  139.                                                   D3DUSAGE_WRITEONLY, D3DFVF_MYVERTEX,
  140.                                                   D3DPOOL_MANAGED, &m_pWallVB ) ) )
  141.     {
  142.         return E_FAIL;
  143.     }
  144.  
  145.     // Fill in the grid vertex data
  146.     m_pWallVB->Lock( 0, 0, (BYTE**)&v, 0 );
  147.     float dX = 1.0f/(m_n-1);
  148.     float dZ = 1.0f/(m_m-1);
  149.     float dU = 1.0f/(m_n-1);
  150.     float dV = 1.0f/(m_m-1);
  151.     UINT k = 0;
  152.     for (UINT z=0; z < (m_m-1); z++)
  153.     {
  154.         for (UINT x=0; x < (m_n-1); x++)
  155.         {
  156.             v[k].p  = D3DXVECTOR3(10 * x*dX, 0.0f, 10 * z*dZ );
  157.             v[k].n  = D3DXVECTOR3(0.0f, 1.0f, 0.0f);
  158.             k++;
  159.             v[k].p  = D3DXVECTOR3(10 * x*dX, 0.0f, 10 * (z+1)*dZ );
  160.             v[k].n  = D3DXVECTOR3(0.0f, 1.0f, 0.0f);
  161.             k++;
  162.             v[k].p  = D3DXVECTOR3(10 * (x+1)*dX, 0.0f, 10 * (z+1)*dZ );
  163.             v[k].n  = D3DXVECTOR3(0.0f, 1.0f, 0.0f);
  164.             k++;
  165.             v[k].p  = D3DXVECTOR3(10 * x*dX, 0.0f, 10 * z*dZ );
  166.             v[k].n  = D3DXVECTOR3(0.0f, 1.0f, 0.0f);
  167.             k++;
  168.             v[k].p  = D3DXVECTOR3(10 * (x+1)*dX, 0.0f, 10 * (z+1)*dZ );
  169.             v[k].n  = D3DXVECTOR3(0.0f, 1.0f, 0.0f);
  170.             k++;
  171.             v[k].p  = D3DXVECTOR3(10 * (x+1)*dX, 0.0f, 10 * z*dZ );
  172.             v[k].n  = D3DXVECTOR3(0.0f, 1.0f, 0.0f);
  173.             k++;
  174.         }
  175.     }
  176.     m_pWallVB->Unlock();
  177.  
  178.     // Create sphere and cone meshes to represent the lights
  179.     if (FAILED( D3DXCreateSphere(m_pd3dDevice, 0.25f, 20, 20, &m_pSphereMesh, NULL) ) )
  180.         return E_FAIL;
  181.  
  182.     if (FAILED( D3DXCreateCylinder(m_pd3dDevice, 0.0f, 0.25f, 0.5f, 20, 20, &m_pConeMesh, NULL) ) )
  183.         return E_FAIL;
  184.  
  185.     // Set up a material
  186.     D3DMATERIAL8 mtrl;
  187.     D3DUtil_InitMaterial( mtrl, 1.0f, 1.0f, 1.0f );
  188.     m_pd3dDevice->SetMaterial( &mtrl );
  189.  
  190.     // Set miscellaneous render states
  191.     m_pd3dDevice->SetRenderState( D3DRS_DITHERENABLE,   FALSE );
  192.     m_pd3dDevice->SetRenderState( D3DRS_SPECULARENABLE, FALSE );
  193.  
  194.     // Set the world matrix
  195.     D3DXMATRIX matIdentity;
  196.     D3DXMatrixIdentity( &matIdentity );
  197.     m_pd3dDevice->SetTransform( D3DTS_WORLD,  &matIdentity );
  198.  
  199.     // Set the view matrix.
  200.     D3DXMATRIX matView;
  201.     D3DXVECTOR3 vFromPt( -10, 10, -10);
  202.     D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f );
  203.     D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );
  204.     D3DXMatrixLookAtLH( &matView, &vFromPt, &vLookatPt, &vUpVec );
  205.     m_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );
  206.  
  207.     // Set the projection matrix
  208.     D3DXMATRIX matProj;
  209.     FLOAT fAspect = ((FLOAT)m_d3dsdBackBuffer.Width) / m_d3dsdBackBuffer.Height;
  210.     D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, fAspect, 1.0f, 100.0f );
  211.     m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
  212.  
  213.     // Turn on lighting.
  214.     m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );
  215.  
  216.     // Enable ambient lighting to a dim, grey light, so objects that
  217.     // are not lit by the other lights are not completely black
  218.     m_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 
  219.         D3DCOLOR_COLORVALUE( 0.25, 0.25, 0.25, 1.0 ) );
  220.  
  221.     // Set light #0 to be a simple, faint grey directional light so 
  222.     // the walls and floor are slightly different shades of grey
  223.     D3DLIGHT8 light;                 // Description of the D3D light
  224.     ZeroMemory( &light, sizeof(light) );
  225.     light.Type = D3DLIGHT_DIRECTIONAL;
  226.     light.Direction = D3DXVECTOR3( 0.3f, -0.5f, 0.2f );
  227.     light.Diffuse.r = light.Diffuse.g = light.Diffuse.b = 0.25f;
  228.     m_pd3dDevice->SetLight( 0, &light );
  229.  
  230.     // Set light #1 to be a simple, bright directional light to use 
  231.     // on the mesh representing light #2
  232.     ZeroMemory( &light, sizeof(light) );
  233.     light.Type = D3DLIGHT_DIRECTIONAL;
  234.     light.Direction = D3DXVECTOR3( 0.5f, -0.5f, 0.5f );
  235.     light.Diffuse.r = light.Diffuse.g = light.Diffuse.b = 1.0f;
  236.     m_pd3dDevice->SetLight( 1, &light );
  237.  
  238.     // Light #2 will be the light used to light the floor and walls.  It will
  239.     // be set up in FrameMove() since it changes every frame.
  240.  
  241.     // Restore the font
  242.     m_pFont->RestoreDeviceObjects();
  243.  
  244.     return S_OK;
  245. }
  246.  
  247.  
  248. //-----------------------------------------------------------------------------
  249. // Name: FrameMove()
  250. // Desc: Called once per frame, the call is the entry point for animating
  251. //       the scene.
  252. //-----------------------------------------------------------------------------
  253. HRESULT CMyD3DApplication::FrameMove()
  254. {
  255.     ZeroMemory( &m_light, sizeof(m_light) );
  256.  
  257.     // Rotate through the various light types
  258.     m_light.Type = (D3DLIGHTTYPE)(1+(((DWORD)m_fTime)/5)%3);
  259.  
  260.     // Make sure the light type is supported by the device.  If 
  261.     // D3DVTXPCAPS_POSITIONALLIGHTS is not set, the device does not support 
  262.     // point or spot lights, so change light #2's type to a directional light.
  263.     DWORD dwCaps = m_d3dCaps.VertexProcessingCaps;
  264.     if( 0 == ( dwCaps & D3DVTXPCAPS_POSITIONALLIGHTS ) )
  265.     {
  266.         if( m_light.Type == D3DLIGHT_POINT || m_light.Type == D3DLIGHT_SPOT )
  267.             m_light.Type = D3DLIGHT_DIRECTIONAL;
  268.     }
  269.  
  270.     // Values for the light position, direction, and color
  271.     FLOAT x = sinf( m_fTime*2.000f );
  272.     FLOAT y = sinf( m_fTime*2.246f );
  273.     FLOAT z = sinf( m_fTime*2.640f );
  274.  
  275.     m_light.Diffuse.r  = 0.5f + 0.5f * x;
  276.     m_light.Diffuse.g  = 0.5f + 0.5f * y;
  277.     m_light.Diffuse.b  = 0.5f + 0.5f * z;
  278.     m_light.Range      = 100.0f;
  279.     
  280.     switch( m_light.Type )
  281.     {
  282.         case D3DLIGHT_POINT:
  283.             m_light.Position     = 4.5f * D3DXVECTOR3( x, y, z );
  284.             m_light.Attenuation1 = 0.4f;
  285.             break;
  286.         case D3DLIGHT_DIRECTIONAL:
  287.             m_light.Direction    = D3DXVECTOR3( x, y, z );
  288.             break;
  289.         case D3DLIGHT_SPOT:
  290.             m_light.Position     = 2.0f * D3DXVECTOR3( x, y, z );
  291.             m_light.Direction    = D3DXVECTOR3( x, y, z );
  292.             m_light.Theta        = 0.5f;
  293.             m_light.Phi          = 1.0f;
  294.             m_light.Falloff      = 1.0f;
  295.             m_light.Attenuation0 = 1.0f;
  296.     }
  297.     m_pd3dDevice->SetLight( 2, &m_light );
  298.  
  299.     return S_OK;
  300. }
  301.  
  302.  
  303.  
  304.  
  305. //-----------------------------------------------------------------------------
  306. // Name: Render()
  307. // Desc: Called once per frame, the call is the entry point for 3d
  308. //       rendering. This function sets up render states, clears the
  309. //       viewport, and renders the scene.
  310. //-----------------------------------------------------------------------------
  311. HRESULT CMyD3DApplication::Render()
  312. {
  313.     // Clear the viewport
  314.     m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET, 0x000000ff, 1.0f, 0L );
  315.  
  316.     // Begin the scene
  317.     if( SUCCEEDED( m_pd3dDevice->BeginScene() ) )
  318.     {
  319.         m_pd3dDevice->SetStreamSource( 0, m_pWallVB, sizeof(MYVERTEX) );
  320.         m_pd3dDevice->SetVertexShader( D3DFVF_MYVERTEX );
  321.  
  322.         D3DXMATRIX matWorld;
  323.         D3DXMATRIX matTrans;
  324.         D3DXMATRIX matRotate;
  325.  
  326.         // Turn on light #0 and #2, and turn off light #1
  327.         m_pd3dDevice->LightEnable( 0, TRUE );
  328.         m_pd3dDevice->LightEnable( 1, FALSE );
  329.         m_pd3dDevice->LightEnable( 2, TRUE );
  330.  
  331.         // Draw the floor
  332.         D3DXMatrixTranslation( &matTrans, -5.0f, -5.0f, -5.0f );
  333.         D3DXMatrixRotationZ( &matRotate, 0.0f );
  334.         matWorld = matRotate * matTrans;
  335.         m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
  336.         m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, m_nTriangles );
  337.  
  338.         // Draw the back wall
  339.         D3DXMatrixTranslation( &matTrans, 5.0f,-5.0f, -5.0f );
  340.         D3DXMatrixRotationZ( &matRotate, D3DX_PI/2 );
  341.         matWorld = matRotate * matTrans;
  342.         m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
  343.         m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, m_nTriangles );
  344.  
  345.         // Draw the side wall
  346.         D3DXMatrixTranslation( &matTrans, -5.0f, -5.0f, 5.0f );
  347.         D3DXMatrixRotationX( &matRotate,  -D3DX_PI/2 );
  348.         matWorld = matRotate * matTrans;
  349.         m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
  350.         m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, m_nTriangles );
  351.  
  352.         // Turn on light #1, and turn off light #0 and #2
  353.         m_pd3dDevice->LightEnable( 0, FALSE );
  354.         m_pd3dDevice->LightEnable( 1, TRUE );
  355.         m_pd3dDevice->LightEnable( 2, FALSE );
  356.  
  357.         // Draw the mesh representing the light
  358.         if( m_light.Type == D3DLIGHT_POINT )
  359.         {
  360.             // Just position the point light -- no need to orient it
  361.             D3DXMatrixTranslation( &matWorld, m_light.Position.x, 
  362.                 m_light.Position.y, m_light.Position.z );
  363.             m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
  364.             m_pSphereMesh->DrawSubset(0);
  365.         }
  366.         else
  367.         {
  368.             // Position the light and point it in the light's direction
  369.             D3DXVECTOR3 vecFrom( m_light.Position.x, m_light.Position.y, m_light.Position.z );
  370.             D3DXVECTOR3 vecAt( m_light.Position.x + m_light.Direction.x, 
  371.                                m_light.Position.y + m_light.Direction.y,
  372.                                m_light.Position.z + m_light.Direction.z );
  373.             D3DXVECTOR3 vecUp( 0, 1, 0);
  374.             D3DXMATRIX matWorldInv;
  375.             D3DXMatrixLookAtLH( &matWorldInv, &vecFrom, &vecAt, &vecUp);
  376.             D3DXMatrixInverse( &matWorld, NULL, &matWorldInv);
  377.             m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
  378.             m_pConeMesh->DrawSubset(0);
  379.         }
  380.  
  381.         // Output statistics
  382.         m_pFont->DrawText( 2,  0, D3DCOLOR_ARGB(255,255,255,0), m_strFrameStats );
  383.         m_pFont->DrawText( 2, 20, D3DCOLOR_ARGB(255,255,255,0), m_strDeviceStats );
  384.         TCHAR* strLight = (m_light.Type == D3DLIGHT_POINT ? TEXT("Point Light") : 
  385.             m_light.Type == D3DLIGHT_SPOT ? TEXT("Spot Light") : TEXT("Directional Light"));
  386.         m_pFont->DrawText( 2, 40, D3DCOLOR_ARGB(255,255,255,255), strLight);
  387.  
  388.         // End the scene.
  389.         m_pd3dDevice->EndScene();
  390.     }
  391.  
  392.     return S_OK;
  393. }
  394.  
  395.  
  396.  
  397.  
  398. //-----------------------------------------------------------------------------
  399. // Name: InvalidateDeviceObjects()
  400. // Desc: Invalidates device objects.  
  401. //-----------------------------------------------------------------------------
  402. HRESULT CMyD3DApplication::InvalidateDeviceObjects()
  403. {
  404.     SAFE_RELEASE( m_pWallVB );
  405.     SAFE_RELEASE( m_pSphereMesh );
  406.     SAFE_RELEASE( m_pConeMesh );
  407.     m_pFont->InvalidateDeviceObjects();
  408.  
  409.     return S_OK;
  410. }
  411.  
  412.  
  413.  
  414.  
  415. //-----------------------------------------------------------------------------
  416. // Name: DeleteDeviceObjects()
  417. // Desc: Called when the app is exiting, or the device is being changed,
  418. //       this function deletes any device dependent objects.  
  419. //-----------------------------------------------------------------------------
  420. HRESULT CMyD3DApplication::DeleteDeviceObjects()
  421. {
  422.     m_pFont->DeleteDeviceObjects();
  423.     SAFE_RELEASE( m_pWallVB );
  424.  
  425.     return S_OK;
  426. }
  427.  
  428.  
  429.  
  430.  
  431. //-----------------------------------------------------------------------------
  432. // Name: FinalCleanup()
  433. // Desc: Called before the app exits, this function gives the app the chance
  434. //       to cleanup after itself.
  435. //-----------------------------------------------------------------------------
  436. HRESULT CMyD3DApplication::FinalCleanup()
  437. {
  438.     // Cleanup D3D font
  439.     SAFE_DELETE( m_pFont );
  440.  
  441.     return S_OK;
  442. }
  443.